package com.ideaaedi.mybatis.data.security.util;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * bean工具类
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 1.4.2-mp3.5.1
 */
public final class BeanUtil {
    
    
    /**
     * 获取对象所有字段名
     *
     * @param obj 目标对象
     *
     * @return  obj对象的所有字段名
     */
    @NonNull
    public static String[] getAllPropertyName(@Nullable Object obj) {
        return getPropertyName(PropertyFilter.ALL, obj);
    }
    
    /**
     * 获取对象所有值为null的字段名
     *
     * @param obj 目标对象
     *
     * @return  对象所有值为null的字段名
     */
    @NonNull
    public static String[] getNullPropertyName(@Nullable Object obj) {
        return getPropertyName(PropertyFilter.NULL, obj);
    }
    
    /**
     * 获取对象所有值不为null的字段名
     *
     * @param obj 目标对象
     *
     * @return  对象所有值不为null的字段名
     */
    @NonNull
    public static String[] getNonNullPropertyName(@Nullable Object obj) {
        return getPropertyName(PropertyFilter.NON_NULL, obj);
    }
    
    /**
     * 获取字段名
     *
     * @param propertyFilter 过滤策略
     * @param obj 目标对象
     *
     * @return  字段名数组
     */
    @NonNull
    private static String[] getPropertyName(@NonNull PropertyFilter propertyFilter, @Nullable Object obj) {
        if (obj == null) {
            return new String[]{};
        }
        final BeanWrapper beanWrapper = new BeanWrapperImpl(obj);
        PropertyDescriptor[] propertyDescriptorArr = beanWrapper.getPropertyDescriptors();
        Set<String> propertyNameSet = new LinkedHashSet<>();
        switch (propertyFilter) {
            case ALL:
                propertyNameSet.addAll(Arrays.stream(propertyDescriptorArr).map(PropertyDescriptor::getName).collect(Collectors.toList()));
                break;
            case NULL:
                propertyNameSet.addAll(Arrays.stream(propertyDescriptorArr).filter(x -> {
                    String propertyName = x.getName();
                    Object propertyValue = beanWrapper.getPropertyValue(propertyName);
                    return propertyValue == null;
                }).map(PropertyDescriptor::getName).collect(Collectors.toList()));
                break;
            case NON_NULL:
                propertyNameSet.addAll(Arrays.stream(propertyDescriptorArr).filter(x -> {
                    String propertyName = x.getName();
                    Object propertyValue = beanWrapper.getPropertyValue(propertyName);
                    return propertyValue != null;
                }).map(PropertyDescriptor::getName).collect(Collectors.toList()));
                break;
            default:
                throw new UnsupportedOperationException("Un-support propertyFilter '" + propertyFilter + "'.");
        }
        return propertyNameSet.toArray(new String[0]);
    }
    
    
    /**
     * 字段过滤器
     */
    enum PropertyFilter {
        ALL("所有字段"),
        NULL("值为null的字段"),
        NON_NULL("值不为null的字段");
        
        private final String desc;
    
        PropertyFilter(String desc) {
            this.desc = desc;
        }
    
        public String getDesc() {
            return desc;
        }
    }
    
}